package com.cheche.dn.common.base;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 基础VO
 * Created by cheshun on 15/12/5.
 */

public abstract class BaseVo<E extends IdEntity> {

    private static final Logger logger = LoggerFactory.getLogger(BaseVo.class);

    private String id;

    protected void setEntity(E e) {
        Map<String, Class<?>> fields = getFields(this.getClass(), new HashMap<String, Class<?>>());
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(e.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property: propertyDescriptors) {
                String field = property.getName();
                if (field.equals(IdEntity.ID_PROPERTY_NAME)) {
                    setId(e.getId().toString());
                    continue;
                }
                Class<?> returnType = fields.get(field);
                if (returnType != null && returnType.equals(property.getPropertyType())) {
                    Method getter = property.getReadMethod();
                    Object obj = getter.invoke(e);
                    Method setter = getMethod(this.getClass(), property.getWriteMethod().getName(), returnType);
                    if (setter != null) {
                        setter.invoke(this, obj);
                    }
                }
            }
        } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e1) {
            logger.error("reflect exception...");
            e1.printStackTrace();
        }
    }

    private Map<String, Class<?>> getFields(Class c, Map<String, Class<?>> fieldMap) {
        if (fieldMap == null)
            return Collections.emptyMap();
        Field[] fields = c.getDeclaredFields();
        for (Field field: fields) {
            fieldMap.put(field.getName(), field.getType());
        }
        Class sc = c.getSuperclass();
        if (sc != null) {
            return getFields(sc, fieldMap);
        }
        return fieldMap;
    }

    private Method getMethod(Class<?> c, String methodName, Class<?> paramType) {
        Method method = null;
        try {
            method = c.getDeclaredMethod(methodName, paramType);
        } catch (NoSuchMethodException ignored) {
        }
        if (method != null)
            return method;
        Class<?> sc = c.getSuperclass();
        if (sc != null)
            return getMethod(sc, methodName, paramType);
        return null;
    }


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
